package com.kurancy.web.controller;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import javax.persistence.TypedQuery;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.kurancy.authentication.config.FacebookConfig;
import com.kurancy.domain.KurancyCreated;
import com.kurancy.domain.KurancyUser;
import com.kurancy.domain.UserAuth;
import com.kurancy.domain.enums.KurancyAmount;
import com.kurancy.domain.enums.KurancyStatus;
import com.kurancy.domain.enums.State;
import com.kurancy.domain.exception.InvalidTokenException;
import com.kurancy.domain.exception.NotFoundException;
import com.kurancy.paypal.config.KurancyPaypalConfig;
import com.kurancy.paypal.services.AdaptiveRequestsService;
import com.kurancy.service.KurancyNoteService;
import com.kurancy.service.kurancycreated.KurancySearchService;
import com.kurancy.web.authentication.service.AuthService;
import com.kurancy.web.controller.form.KurancyCreatedSearchForm;
import com.kurancy.web.controller.form.KurancyPaypalSearchForm;
import com.kurancy.web.util.DropdownUtil;
import com.paypal.adaptive.api.requests.PaymentDetailsRequest;
import com.paypal.adaptive.api.responses.PaymentDetailsResponse;

@RequestMapping("/myKurancy/**")
@Controller
public class MyKurancyController {

    @Autowired
	private KurancySearchService kurancySearchService;
    
	@Autowired
	private KurancyPaypalConfig paypalConfig;
    
	@Autowired
	private KurancyNoteService kurancyNoteService;
	
	@Autowired
	private FacebookConfig facebookConfig;
	
	@Autowired
	private AuthService authService;
	
	@Autowired
	private AdaptiveRequestsService adaptiveRequestsService;

	/** The logger. */
	private static Log logger = LogFactory.getLog(MyKurancyController.class);

	@RequestMapping(method = RequestMethod.GET)
    public String index(ModelMap map, Model uiModel, HttpServletRequest request) {
		
		logger.debug("Started:");
		
		Authentication storedAuth = SecurityContextHolder.getContext().getAuthentication();
		if (storedAuth instanceof UsernamePasswordAuthenticationToken) {
			authService.cacheNonFacebookAuthentication(storedAuth, request);
		} else {
			UserAuth userAuth = (UserAuth)storedAuth;
		
			if (userAuth.getKurancyUser().getFacebookUserId() != null) {
		        TypedQuery<KurancyCreated> tp = KurancyCreated.findKurancyCreatedsByCreatedByEquals(userAuth.getKurancyUser().getFacebookUserId());
		        List<KurancyCreated> list = tp.getResultList();
		        
		        for (KurancyCreated created: list) {
		        	if (created.getPaypalPayKey() != null && created.getStatus().equals(KurancyStatus.PENDING)) {
		        		
						try {
							PaymentDetailsResponse response = adaptiveRequestsService.processPaymentDetails(created.getPaypalPayKey());
							logger.debug(response.getPaymentDetails().getStatus());
						} catch (IOException e) {
							logger.error(e,e);
						}
		        	}
		        }
		        uiModel.addAttribute("kurancyCreateds", tp.getResultList());
			}
		}
		
		createSearchForm(map, null);
			
		return "myKurancy/index";
	}
	
	@RequestMapping("/create")
    public String create(ModelMap map, Model uiModel, HttpServletRequest httpServletRequest) {
		
		logger.debug("Started:");
		
	    uiModel.addAttribute("kurancyCreated", new KurancyCreated());
	    uiModel.addAttribute("kurancyAmounts", DropdownUtil.createNameValuePairsFromEnum(KurancyAmount.values(), "getValue", "getValue", false));
	
		return "myKurancy/create";
	}
	
	@RequestMapping(value="/create", method = RequestMethod.POST)
	public String submitCreate(@Valid KurancyCreated templateKurancyCreated, BindingResult bindingResult, ModelMap map, Model uiModel, HttpServletRequest req) throws NoSuchAlgorithmException {
		
		logger.debug("Started:");
		
        if (bindingResult.hasErrors()) {
            populateEditForm(uiModel, templateKurancyCreated);
            return "kurancycreateds/update";
        }
        uiModel.asMap().clear();
        
        	KurancyUser kurancyUser = authService.getKurancyUser();
        	
        	try {
				kurancyNoteService.generateKurancyNotePage(6, templateKurancyCreated, kurancyUser);
			} catch (Exception e) {
				 populateEditForm(uiModel, templateKurancyCreated);
		         return "kurancycreateds/update";
			}
        
        return index(map, uiModel, req);
    }

	@RequestMapping(value="/redeem", method = RequestMethod.GET)
    public String redeem(@Valid KurancyCreatedSearchForm searchForm, BindingResult bindingResult, ModelMap map, Model uiModel, HttpServletRequest httpServletRequest) {
		
		logger.debug("Started:");
		if (bindingResult.hasErrors()) {
			createSearchForm(map, searchForm);
			return "myKurancy/index";
        }
		
		String tokenA = searchForm.getKurancyToken();
    	String compositeToken = tokenA + tokenB;
    	   	
    	try {
    		KurancyStatus status = kurancySearchService.validateToken(compositeToken);
	    	
    		if (status.equals(KurancyStatus.ACTIVE) ) {
	    		return currencyFound(map, compositeToken);
	    	} else  {
	    		createSearchForm(map, searchForm);
	    		bindingResult.rejectValue("kurancyToken", "kurancy.token." + status.getValue());
	    		return "myKurancy/redeem";
	    	}
    	} catch (NotFoundException e) {
    		createSearchForm(map, searchForm);
    		bindingResult.rejectValue("kurancyToken", "kurancy.token.not.found");
    		return "homepage/index";
    	} catch (InvalidTokenException e) {
    		createSearchForm(map, searchForm);
    		bindingResult.rejectValue("kurancyToken", "kurancy.token.invalid");
    		return "homepage/index";
    	}
	
		
	}
	
	private String currencyFound(ModelMap map, String compositeToken) {
		KurancyPaypalSearchForm searchForm = new KurancyPaypalSearchForm();
		searchForm.setKurancyToken(compositeToken);
    	map.addAttribute("kurancyPaypalSearchForm", searchForm);
		return "claimKurancy";
	}
	
	@RequestMapping("/pay")
    public String pay(@RequestParam (required=true, value="identifier") String kurancyToken, 
    		@RequestParam (required=true, value="paypalVersion") Integer paypalVersion,
    		ModelMap map, HttpServletRequest httpServletRequest) {
		
		logger.debug("Started:");
		
		KurancyCreated kurancyCreated = null;
		try {
			
			try {
				kurancyCreated = kurancySearchService.getKurancyCreatedByToken(kurancyToken);
			} catch (Exception e) {
				logger.error ("Invalid Token: " + kurancyToken);
			}
			if (kurancyCreated != null) {
				adaptiveRequestsService.processChainedPayRequest(httpServletRequest.getRemoteAddr(), kurancyCreated);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		//map.addAttribute("paypalPayKey", paypalPayKey);
		map.addAttribute("paypalPaymentsUrl", paypalConfig.getPaypalPaymentsUrl());
		map.addAttribute("kurancyCreated", kurancyCreated);
	
		return "myKurancy/paypal" + paypalVersion;
	}
	
	@RequestMapping("/payment/return")
    public String paymentReturn(@RequestParam (required=true, value="payKey") String payKey, ModelMap map, HttpServletRequest httpServletRequest) {
		logger.debug("Paykey completed:" + payKey);
		
		return "myKurancy/paypal/completed";
	}
	
	@RequestMapping("/payment/cancel")
    public String paymentCancelled(@RequestParam (required=true, value="payKey") String payKey, ModelMap map, HttpServletRequest httpServletRequest) {
		logger.debug("Paykey cancelled:" + payKey);
		
		return "myKurancy/paypal/completed";
	}
	
	
	@RequestMapping("/update")
    public String update(ModelMap map, Model uiModel, HttpServletRequest httpServletRequest) {
		
		logger.debug("Started:");
	
		return "myKurancy/update";
	}
	
	@RequestMapping("/claim/updatePaypal")
	public String updatePaypal(@Valid KurancyPaypalSearchForm searchForm, BindingResult bindingResult, ModelMap map, Model uiModel, HttpServletRequest httpServletRequest) {
		
		if (!searchForm.getCredential().equals(searchForm.getCredentialVerify())) {
			bindingResult.reject("claim.credentials.must.match");
		}
		if (bindingResult.hasErrors()) {
			uiModel.addAttribute("kurancyPaypalSearchForm", searchForm);
			return "claim/getPaypalInfo";
		}
		
		// paypal credentials were well formed and matched each other
		authService.updatePaypalCredentials(searchForm.getCredential().trim());
		
		kurancyNoteService.markNoteClaimed(searchForm.getKurancyToken());
		
		return "myKurancy/index";
	}
	
	private void createSearchForm(ModelMap map, KurancyCreatedSearchForm existingForm) {
		KurancyCreatedSearchForm form = null;
		if (existingForm == null) {
			form = new KurancyCreatedSearchForm();
    		map.addAttribute("searchForm", form);
		} else { 
			map.addAttribute("searchForm", existingForm);
		}
	}
	
    void populateEditForm(Model uiModel, KurancyCreated kurancyCreated) {
        uiModel.addAttribute("kurancyCreated", kurancyCreated);
    }
    
    @ModelAttribute("loginRedirectUrl")
	public String getLoginRedirectUrl(){
		
		logger.debug("start:");
		
		return facebookConfig.getLoginRedirectURL();
	}
    
}
